package co.infinum.goldfinger;

import co.infinum.goldfinger.crypto.ReprintModule;
import co.infinum.goldfinger.util.LogUtils;
import ohos.aafwk.ability.Ability;
import ohos.biometrics.authentication.BiometricAuthentication;

import java.util.concurrent.atomic.AtomicReference;

public interface Goldfinger {

    public void registerModule(ReprintModule module);

    public int isHardwarePresent();

    /**
     * Start an authentication request.
     *
     * @param callback         The listener to be notified.
     * @param restartPredicate The predicate that determines whether to restart or not.
     */
    public void authenticate(RestartPredicate restartPredicate, Callback callback);

    /**
     * Returns BA_SUCCESS if the authentication is canceled; returns BA_FAILED otherwise.
     * 取消认证
     *
     * @return int
     */
    public int cancelAuthentication();

    boolean canAuthenticate();

    /**
     * Authenticate user via Fingerprint. If user is successfully authenticated,
     * <p>
     * Use it when saving some data that should not be saved as plain text (e.g. password).
     * To decrypt the value use {@link Goldfinger#} method.
     * <p>
     * Example - Allow auto-login via Fingerprint.
     *
     * @param restartPredicate parameters used to build {@link } instance
     * @param key              unique key identifier, used to store cipher IV internally
     * @param value            String value which will be encrypted if user successfully authenticates
     * @param callback         callback
     * @see Goldfinger.Callback
     */
    void encrypt(
            RestartPredicate restartPredicate,
            String key,
            String value,
            Callback callback
    );

    /**
     * Become Bob the builder.
     */

    /**
     * Callback used to receive Goldfinger results.
     */


    /**
     * A listener that is notified of the results of fingerprint authentication.
     * 认证结果监听器
     */
    interface Callback {
        /**
         * Called after a fingerprint is successfully authenticated.
         *
         * @param result The {@link ReprintModule#tag()} of the module that was used for authentication.
         */
        void onResult(Result result);

        /**
         * Called after an error or authentication failure.
         *
         * @param e The specific error code returned by the module's underlying sdk. Check the
         *          constants defined in the module for possible values and their meanings.
         */
        void onError(Throwable e);
    }


    interface Logger {
        void log(String message);

        void logException(Throwable throwable, String message);
    }

    interface RestartPredicate {
        /**
         * Return true if the authentication should be restarted after the given non-fatal failure.
         *
         * @param reason       The reason for this failure.
         * @param restartCount The number of times this authentication call has already been
         *                     restarted.
         * @return  boolean
         */
        boolean invoke(BiometricAuthentication.AuthenticationTips reason, int restartCount);
    }


    /**
     * Result wrapper class containing all the useful information about
     * fingerprint authentication and value for encryption/decryption operations.
     */
    class Result {
        private Type type;
        private int reason;
        private String value;
        private String message;
        private int code = -1;
        private int tag;
        private boolean fatal = false;

        public Result(Type type) {
            this(type, null, null);
        }

        public Result(Type type, String value, String message) {
            this.type = type;
            this.value = value;
            this.message = message;
        }

        public Result(Type type, int reason, String value, String message, int code, int tag) {
            this.type = type;
            this.reason = reason;
            this.value = value;
            this.message = message;
            this.code = code;
            this.tag = tag;
        }

        public Result(Type type, int reason, String value, String message, int code, int tag, boolean fatal) {
            this.type = type;
            this.reason = reason;
            this.fatal = fatal;
            this.value = value;
            this.message = message;
            this.code = code;
            this.tag = tag;
        }

        public String message() {
            return message;
        }

        public Type type() {
            return type;
        }

        public String value() {
            return value;
        }

        public int code() {
            return code;
        }

        public int tag() {
            return tag;
        }

        public int reason() {
            return reason;
        }

        public boolean fatal() {
            return fatal;
        }
    }

    class Builder {
        private AtomicReference<BiometricAuthentication> cancellationSignal = new AtomicReference<>();
        private ReprintModule module;
        private Ability context;
        private BiometricAuthentication.SecureLevel level;
        private BiometricAuthentication.AuthType type;
        private Logger logger;

        public Goldfinger build() {
            return buildGoldfinger();
        }

        public Builder(Ability context) {
            this.context = context;
        }

        public Builder setSecureLevel(BiometricAuthentication.SecureLevel level) {
            this.level = level;
            return this;
        }

        public Builder setAuthType(BiometricAuthentication.AuthType type) {
            this.type = type;
            return this;
        }

        public Builder setLogger(Goldfinger.Logger logger) {
            this.logger = logger;
            return this;
        }

        public Builder logEnabled(boolean logEnabled) {
            LogUtils.setEnabled(logEnabled);
            return this;
        }

        private Goldfinger buildGoldfinger() {
            return new GoldfingerImpl(context, type, level, logger);
        }
    }

    /**
     * Describes the type of the result received in {@link Callback#onResult}
     */
    enum Type {

        /**
         * Fingerprint authentication is successfully finished. {@link Goldfinger.Result}
         */
        SUCCESS,

        /**
         * Fingerprint authentication is still active. {@link Goldfinger.Result} contains
         * additional information about currently active fingerprint authentication.
         */
        INFO,

        /**
         * Fingerprint authentication is unsuccessfully finished. {@link Goldfinger.Result}
         * contains the reason why the authentication failed.
         */
        ERROR
    }

}
